#include "Account.h"
using namespace std;

//@author A0088381W
Account::Account() {
	obtainExpense();
	obtainIncome();
	obtainLoan();
	obtainWish();
}

//@author U095387X
void Account::saveAccount(){
	writeToExpense();
	writeToIncome();
	writeToLoan();
	writeToWish();
}

//@author A0088381W
// this function is to read expense list from file
// file will be in format:
/*	nameExpense1
	amount1 timeOfRecord1 timeOfInput1 method1 category1
	remark1
	nameExpense2
	amount12 timeOfRecord2 timeOfInput2 method2 category2
	remark2
*/
void Account::obtainExpense(){
	ifstream readFile("expense.txt") ;
	
	Expense* newExpense = NULL;
	
	string name, remark, line;
	
	while ( getline(readFile, name)) {
		// get second line
		getline(readFile, line);
		getline (readFile, remark);
		newExpense = new Expense(name, line, remark);

		_ExpenseList.push_back(*newExpense);
	}
	readFile.close();
	return;
}

//@author A0088381W
// This function is to read list of income from file
// file will be in format:
/*	nameIncome1
	amount1 timeOfRecord1 timeOfInput1
	remark1
	nameIncome2
	amount2 timeOfRecord2 timeOfInput2
	remark2
*/
void Account::obtainIncome(){
	ifstream readFile("income.txt") ;
	
	Income* newIncome = NULL;
	string name, line, remark;
	
	while ( getline (readFile, name)) {
		getline (readFile, line);
		getline (readFile, remark);
		newIncome = new Income(name, line, remark);

		_IncomeList.push_back(*newIncome);
	}

	readFile.close();
	return;
}

//@author A0088381W
// This function is to read list of loan from file
// file will be in format:
/*	nameLoan1
	amount1 timeOfRecord1 timeOfInput1
	remark1
	nameLoan2
	amount2 timeOfRecord2 timeOfInput2
	remark2
*/

void Account::obtainLoan(){
	ifstream readFile("loan.txt") ;
	
	Loan* newLoan = NULL;
	string name, remark, line;
	
	while ( getline(readFile, name)) {
		// get second line
		getline(readFile, line);
		getline (readFile, remark);
		newLoan = new Loan(name, line, remark);

		_LoanList.push_back(*newLoan);
	}
	readFile.close();
	return;
}

//@author A0088381W
// This function is to read list of wish from file
// file will be in format:
/*	nameWish1
	amount1 timeOfInput1 expectedDate1
	nameWish2
	amount12 timeOfInput2 expectedDate2
*/
void Account::obtainWish(){
	ifstream readFile("wish.txt") ;
	
	Wish* newWish = NULL;
	string name, line;
	
	while ( getline (readFile, name)) {
		getline (readFile, line);
		newWish = new Wish(name, line);

		_WishList.push_back(*newWish);
	}

	readFile.close();
	return;
}

//@author A0088381W
// this function is to write expense list to a file
// file will be in format:
/*	nameExpense1
	amount1 timeOfRecord1 timeOfInput1 method1 category1
	remark1
	nameExpense2
	amount12 timeOfRecord2 timeOfInput2 method2 category2
	remark2
*/
void Account::writeToExpense() {
	string test;
	ofstream writeFile("expense.txt");
	list<Expense>::iterator iter = _ExpenseList.begin();
	// return if list is empty
	if (_ExpenseList.empty()) {
		writeFile.close();
		return;
	}
	// write the first expense ( without endl before write name )
		writeFile << iter->serialize();
		test=iter->serialize();
		iter++;
	

	// write the rest if list
	while ( iter!= _ExpenseList.end() ) {
		writeFile << endl << iter->serialize();
		iter++;
	}
	writeFile.close();
}

//@author A0088381W
// This function is to write list of income to file
// file will be in format:
/*	nameIncome1
	amount1 timeOfRecord1 timeOfInput1
	remark1
	nameIncome2
	amount2 timeOfRecord2 timeOfInput2
	remark2
*/
void Account::writeToIncome() {
	ofstream writeFile("income.txt");
	list<Income>::iterator iter = _IncomeList.begin();

	// return if list is empty
	if (_IncomeList.empty()) {
		writeFile.close();
		return;
	}

	// write the first income ( without endl before write name of Income )
		writeFile << iter->serialize();
		iter++;


	while ( iter!= _IncomeList.end() ) {
		writeFile << endl << iter->serialize();
		iter++;
	}
	writeFile.close();
}

//@author A0088381W
// This function is to write list of loan to file
// file will be in format:
/*	nameLoan1
	amount1 timeOfRecord1 timeOfInput1
	remark1
	nameLoan2
	amount2 timeOfRecord2 timeOfInput2
	remark2
*/
void Account::writeToLoan() {
	ofstream writeFile("loan.txt");
	list<Loan>::iterator iter = _LoanList.begin();

	// return if list is empty
	if (_LoanList.empty()) {
		writeFile.close();
		return;
	}

	// write the first loan ( without endl before write name of loan)
	writeFile << iter->serialize();
	iter++;

	while ( iter!= _LoanList.end() ) {
		writeFile << endl << iter->serialize();
		iter++;
	}
	writeFile.close();
}

//@author A0088381W
// This function is to read list of wish from file
// file will be in format:
/*	nameWish1
	amount1 timeOfInput1 expectedDate1
	nameWish2
	amount12 timeOfInput2 expectedDate2
*/
void Account::writeToWish() {
	ofstream writeFile("wish.txt");
	list<Wish>::iterator iter = _WishList.begin();

	// return if list is empty
	if (_WishList.empty()) {
		writeFile.close();
		return;
	}

	// write the first wish ( without endl before write name of wish)
	writeFile << iter->serialize();
	iter++;

	while ( iter!= _WishList.end() ) {
		writeFile << endl << iter->serialize();
		iter++;
	}
	writeFile.close();
}

//@author A0088381W
// This function is to take in a range of time and return a list of expenses which has timeOfRecord falling in the range
list<Expense> Account::readExpense(time_t startTime, time_t endTime){
	list<Expense> result;
	// return empty list if no element
	if ( _ExpenseList.empty() )
		return result;

	list<Expense>::iterator iter = _ExpenseList.begin();
	bool larger = false;
	// push_back *iter if startTime < iter->_timeOfRecord < EndTime
	// end loop when hit the end of list or current iter->_timeOfRecord > endTime
	while ( (iter != _ExpenseList.end()) && !larger) {
		if ((iter->getTimeOfRecord() >= startTime) && (iter->getTimeOfRecord() <= endTime ) )
			result.push_back(*iter);
		if (iter->getTimeOfRecord() > endTime)
			larger = true;
		iter++;
	}

	return result;

}

//@author A0088381W
// This function is to take in a range of time and return a list of incomes which has endDate falling in the range
list<Income> Account::readIncome(time_t startTime, time_t endTime){
	list<Income> result;
	// return empty list if no element
	if ( _IncomeList.empty() )
		return result;

	list<Income>::iterator iter = _IncomeList.begin();
	bool larger = false;
	// push_back *iter if startTime < iter->_timeOfRecord < EndTime
	// end loop when hit the end of list or current iter->_timeOfRecord > endTime
	while ( (iter != _IncomeList.end()) && !larger) {
		if ((iter->getTimeOfRecord() >= startTime) && (iter->getTimeOfRecord() <= endTime ) )
			result.push_back(*iter);
		if (iter->getTimeOfRecord() > endTime)
			larger = true;
		iter++;
	}

	return result;
}


//@author A0088381W
// This function is to take in a range of time and return a list of loans which has _timeOfRecord falling in the range
list<Loan> Account::readLoan(time_t startTime, time_t endTime){
	list<Loan> result;
	// return empty list if no element
	if ( _LoanList.empty() )
		return result;

	list<Loan>::iterator iter = _LoanList.begin();
	bool larger = false;
	// push_back *iter if startTime < iter->_TimeOfRecord < EndTime
	// end loop when hit the end of list or current iter->_timeOfRecord > endTime
	while ( (iter != _LoanList.end()) && !larger) {
		if ((iter->getTimeOfRecord() >= startTime) && (iter->getTimeOfRecord() <= endTime ) )
			result.push_back(*iter);
		if (iter->getTimeOfRecord() > endTime)
			larger = true;
		iter++;
	}

	return result;

}

//@author A0088381W
list<Loan> Account::readLoan() {
	return _LoanList;
}


//@author A0088381W
// This function is to take in a range of time and return a list of wishes which has _expectedDate falling in the range
list<Wish> Account::readWish(time_t startTime, time_t endTime){
	list<Wish> result;
	// return empty list if no element
	if ( _WishList.empty() )
		return result;

	list<Wish>::iterator iter = _WishList.begin();
	bool larger = false;
	// push_back *iter if startTime < iter->_expectedDate < EndTime
	// end loop when hit the end of list or current iter->_expectedDate > endTime
	while ( (iter != _WishList.end()) && !larger) {
		if ((iter->getExpectedDate() >= startTime) && (iter->getExpectedDate() <= endTime ) )
			result.push_back(*iter);
		if (iter->getExpectedDate() > endTime)
			larger = true;
		iter++;
	}

	return result;

}

//@author A0088381W
list<Wish> Account::readWish() {
	return _WishList;
}

//@author A0088381W
//this function is to add new expense
void Account::addExpense(Expense &newExpense){
	_ExpenseList.push_back(newExpense);
	// sort list after add new item
	_ExpenseList.sort([](Expense & a, Expense & b) { return ((a.getTimeOfRecord()) < (b.getTimeOfRecord())); });
	// rewrite the expense file for update
	writeToExpense();
}

//@author A0088381W
//this function is to add new income
void Account::addIncome(Income newIncome){
	_IncomeList.push_back(newIncome);
	// sort list after add new item
	_IncomeList.sort([](Income & a, Income & b) { return a.getTimeOfRecord() < b.getTimeOfRecord(); });
	// rewrite the income file for update
	writeToIncome();
}

//@author A0088381W
//this function is to add new Loan
void Account::addLoan(Loan newLoan){
	_LoanList.push_back(newLoan);
	// sort list after add new item
	_LoanList.sort([](Loan & a, Loan & b) { return a.getTimeOfRecord() < b.getTimeOfRecord(); });
	// rewrite the income file for update
	writeToLoan();
}

//@author A0088381W
//this function is to add new Wish
void Account::addWish(Wish newWish){
	_WishList.push_back(newWish);
	// sort list after add new item
	_WishList.sort([](Wish & a, Wish & b) { return a.getExpectedDate() < b.getExpectedDate(); });
	// rewrite the income file for update
	writeToWish();
}

//@author A0088381W
void Account::deleteExpense(Expense dExpense){
	bool found = false;
	list<Expense>::iterator iter = _ExpenseList.begin();
	while ( (iter != _ExpenseList.end()) && !found ) {
		if ( iter->getTimeOfInput() == dExpense.getTimeOfInput() ) {
			iter = _ExpenseList.erase(iter);
			found = true;
			break;
		}
		iter++;
	}
	writeToExpense();
	return;
}

//@author A0088381W
void Account::deleteIncome(Income dIncome){
	bool found = false;
	list<Income>::iterator iter = _IncomeList.begin();
	while ( (iter != _IncomeList.end()) && !found ) {
		if ( iter->getTimeOfInput() == dIncome.getTimeOfInput() ) {
			iter = _IncomeList.erase(iter);
			found = true;
			break;
		}
			iter++;
	}
	writeToIncome();
	return;
}

//@author A0088381W
void Account::deleteWish(Wish dWish){
	bool found = false;
	list<Wish>::iterator iter = _WishList.begin();
	while ( (iter != _WishList.end()) && !found ) {
		if ( iter->getTimeOfInput() == dWish.getTimeOfInput() ) {
			iter = _WishList.erase(iter);
			found = true;
			break;
		}
			iter++;
	}
	writeToWish();
	return;
}

//@author A0088381W
void Account::deleteLoan(Loan dLoan){
	bool found = false;
	list<Loan>::iterator iter = _LoanList.begin();
	while ( (iter != _LoanList.end()) && !found ) {
		if ( iter->getTimeOfInput() == dLoan.getTimeOfInput() ) {
			iter = _LoanList.erase(iter);
			found = true;
			break;
		}
			iter++;
	}
	writeToLoan();
	return;
}

//@author A0088381W
list<Expense> Account::findCategory( e_category num, int startTime, int endTime) {
	list<Expense> result;
	// return empty list if no element
	if ( _ExpenseList.empty() )
		return result;

	list<Expense>::iterator iter = _ExpenseList.begin();
	bool larger = false;
	// push_back *iter if startTime < iter->_timeOfRecord < EndTime
	// end loop when hit the end of list or current iter->_timeOfRecord > endTime
	while ( (iter != _ExpenseList.end()) && !larger) {
		if ((iter->getTimeOfRecord() >= startTime) && (iter->getTimeOfRecord() <= endTime ) ) {
			if (iter->getCategory() == num)
				result.push_back(*iter);
		}
		if (iter->getTimeOfRecord() > endTime)
			larger = true;
	}

	return result;
}